﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Sockets;
using System.Net;
using System.Configuration;
using System.Threading;
using System.Xml;
using System.Xml.Linq;
using System.IO;

namespace APJunktion.ATP.UDPClient.Module.Main.Views
{
    /// <summary>
    /// Interaction logic for Main.xaml
    /// </summary>
    public partial class Main : UserControl
    {

        #region Properties
        
        private UdpClient _server;
        private IPEndPoint _receivePoint;
        private int _port;
        private IPAddress _ip;
        private bool _run = false;
        private Thread _startServer;        
        private int _ipacket = 0;
        private bool _logxmlfile = false;
        private FileInfo _fileinfo;
        
        #endregion

        #region Init
        public Main()
        {
            InitializeComponent();
            _fileinfo = new FileInfo(Application.ResourceAssembly.Location);
            int.TryParse(ConfigurationManager.AppSettings.Get("Port"), out _port);
            _ip = IPAddress.Parse(ConfigurationManager.AppSettings.Get("IPAddress"));
            txtIP.Text = _ip.ToString();
            txtPort.Text = _port.ToString();
        }
        #endregion

        #region Private Delegates

        private delegate void UpdateTextCallback(string message, Brush brush); 
        
        #endregion        

        #region Private Methods

        private void UpdateText(string message, Brush brush)
        {
            if (cbLogToFile.IsChecked == true)
            {                
                _logxmlfile = true;                
            }
            else
            {
                _logxmlfile = false;
            }

            if (rtbMessages.Document.Blocks.Count == 100)
            {
                rtbMessages.Document.Blocks.Clear();
                AddMessage("Cleared Log...", Brushes.White);                
            }

            AddMessage(message, brush);
        }

        private void AddMessage(string message, Brush brush)
        {
            Paragraph para = new Paragraph();
            para.Foreground = brush;
            para.Inlines.Add(message);
            rtbMessages.Document.Blocks.Add(para);
            rtbMessages.ScrollToEnd();
        }

        private void WriteXml(string message)
        {
            if (_logxmlfile)
            {
                try
                {
                    _ipacket += 1;
                    PacketConverter.PacketConverter _PacketConverter = new PacketConverter.PacketConverter();
                    XDocument xd = _PacketConverter.ConvertToXML(message);

                    rtbMessages.Dispatcher.Invoke(new UpdateTextCallback(this.UpdateText), new object[] { "Successfully converted packet to XML", Brushes.Green });

                    if (Directory.Exists(_fileinfo.DirectoryName + "\\packets") == false)
                    {
                        Directory.CreateDirectory(_fileinfo.DirectoryName + "\\packets");
                    }

                    xd.Save("packets\\packet" + _ipacket.ToString() + ".xml");

                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        private void start_server()
        {
            _run = true;
            rtbMessages.Dispatcher.Invoke(new UpdateTextCallback(this.UpdateText), new object[] { "Server Started...", Brushes.White });

            //Infinite loop
            while (_run)
            {
                try
                {
                    rtbMessages.Dispatcher.Invoke(new UpdateTextCallback(this.UpdateText), new object[] { "Waiting for Packet on IP Address: " + _receivePoint.Address.ToString() + " Port: " + _receivePoint.Port.ToString() + " Internet Address: " + _receivePoint.AddressFamily.ToString(), Brushes.White });
                    byte[] recData = _server.Receive(ref _receivePoint);
                    rtbMessages.Dispatcher.Invoke(new UpdateTextCallback(this.UpdateText), new object[] { "Packet Received...", Brushes.Yellow });
                    System.Text.ASCIIEncoding encode = new System.Text.ASCIIEncoding();
                    string _message = encode.GetString(recData);
                    WriteXml(_message);
                    rtbMessages.Dispatcher.Invoke(new UpdateTextCallback(this.UpdateText), new object[] { _message, Brushes.GreenYellow });

                }
                catch (Exception ex)
                {
                    rtbMessages.Dispatcher.Invoke(new UpdateTextCallback(this.UpdateText), new object[] { ex.Message, Brushes.Red });
                }
            }
        }         
        
        #endregion

        #region Private Events

        private void btnStartListener_Click(object sender, RoutedEventArgs e)
        {
            btnStartListener.IsEnabled = false;
            _server = new UdpClient(_port);
            _receivePoint = new IPEndPoint(_ip, _port);
            _startServer = new Thread(new ThreadStart(start_server));
            _startServer.Start();
            btnStopListner.IsEnabled = true;            
        }

        private void btnStopListner_Click(object sender, RoutedEventArgs e)
        {
            _startServer.Abort();
            _server.Close();
            btnStopListner.IsEnabled = false;
            btnStartListener.IsEnabled = true;
        }

        private void btnClearLog_Click(object sender, RoutedEventArgs e)
        {
            rtbMessages.Document.Blocks.Clear();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            double deskHeight = SystemParameters.WorkArea.Height;
            double deskWidth = SystemParameters.WorkArea.Width;

            winMain.Height = deskHeight;
            winMain.Width = deskWidth;

            gridMain.Width = deskWidth - 8;
            gridMain.Height = deskHeight - 80;
            rectangle1.Width = deskWidth - 40;

            rtbMessages.Width = deskWidth - 40;
            rtbMessages.Height = deskHeight - 350;
        }

        private void rtbMessages_GotFocus(object sender, RoutedEventArgs e)
        {

        }

        #endregion

    }
}
